package com.ybg.block.core.eth.remoteapi;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.ybg.block.core.eth.config.EthHttpServiceProperties;
import com.ybg.block.framework.api.YbgGeth;
import com.ybg.framework.vo.R;
import com.ybg.share.core.eth.EthGethRemoteApi;
import com.ybg.share.core.eth.vo.EthNodeInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.Web3jService;
import org.web3j.protocol.admin.Admin;
import org.web3j.protocol.core.Request;

import java.io.IOException;
import java.math.BigInteger;
import java.util.Collections;

/**
 * Geth 操作接口
 *
 * @author yanyu
 * @since 2019-11-16
 */
@Slf4j
@Service(version = "${dubbo.provider.version}", timeout = 120000, cache = "false")
public class EthGethRemoteApiImpl implements EthGethRemoteApi {
    @Autowired
    private YbgGeth geth;
    @Autowired
    Web3j web3j;
    @Autowired
    Admin admin;
    @Autowired
    private EthHttpServiceProperties ethHttpServiceProperties;
    @Autowired
    Web3jService web3jService;

    @Override
    public R<Boolean> minerStart(int threadNum) {

        try {
            String address = geth.ethCoinbase().send().getAddress();

            if (StrUtil.isAllBlank(address)) {
                throw new RuntimeException("操作失败，没有创建或者可用的挖矿账号");
            }
            boolean mining = geth.ethMining().send().isMining();
            log.info("挖矿状态：" + mining);
            if (mining) {
                return R.fail("操作失败，已经在挖矿了");
            }
            log.info("发送挖矿请求");
            geth.minerStart(threadNum).send();
            return R.success(true);
        } catch (Exception e) {
            log.error("{}", e);
            return R.fail("操作失败");
        }
    }

    @Override
    public R<Boolean> minerStop() {
        try {
            //   boolean success = geth.minerStop().send().success();
            new Request(
                    "miner_stop", Collections.<String>emptyList(), web3jService, Void.class).send();
            return R.success(true);
        } catch (IOException e) {
            log.error("{}", e);
            return R.fail("操作失败");
        }
    }

    @Override
    public R<String> importRawKey(String keydata, String password) {

        try {
            String accountId = geth.personalImportRawKey(keydata, password).send().getAccountId();
            if (log.isDebugEnabled()) {
                log.info("生成的账号:{}", accountId);
            }
            return R.success(accountId);
        } catch (IOException e) {
            log.error("{}", e);
            return R.fail("操作失败");
        }

    }

    @Override
    public R<Boolean> lockAccount(String accountId) {
        try {
            boolean success = geth.personalLockAccount(accountId).send().success();
            return R.success(success);
        } catch (IOException e) {
            log.error("{}", e);
            return R.fail("操作失败");
        }
    }

    @Override
    public R<String> ecRecover(String message, String signiture) {
        try {
            String recoverAccountId = geth.personalEcRecover(message, signiture).send().getRecoverAccountId();
            return R.success(recoverAccountId);
        } catch (IOException e) {
            log.error("{}", e);
            return R.fail("操作失败");
        }

    }

    @Override
    public R<String> sign(String message, String accountId, String password) {
        //http://cw.hubwiz.com/card/c/geth-rpc-api/1/4/7/
        try {
            String signedMessage = geth.personalSign(message, accountId, password).send().getSignedMessage();
            return R.success(signedMessage);
        } catch (IOException e) {
            e.printStackTrace();
            log.error("{}", e);
            return R.fail("操作失败");
        }
    }

    @Override
    public R<String> getCoinbase() {
        try {
            String address = geth.ethCoinbase().send().getAddress();
            return R.success(address);
        } catch (IOException e) {
            log.error("{}", e);
            return R.fail("查询失败");
        }

    }

    @Override
    public R<Boolean> mining() {
        try {
            boolean mining = geth.ethMining().send().isMining();
            log.info("挖矿状态：" + mining);
            return R.success(mining);
        } catch (IOException e) {
            log.info("{}", e);
            return R.fail("操作失败");
        }
    }

    @Override
    public R<Boolean> setEtherbase(String accountId) {
        try {

            Boolean result = geth.setEtherbase(accountId).send().getResult();
            return R.success(result);
        } catch (IOException e) {
            log.error("{}", e);
            return R.fail("操作失败");
        }

    }

    @Override
    public R<BigInteger> getBlockNumber() {
        try {
            BigInteger blockNumber = geth.ethBlockNumber().send().getBlockNumber();
            return R.success(blockNumber);
        } catch (IOException e) {
            log.error("{}", e);
            return R.fail("操作失败");
        }

    }

    @Override
    public R<String> getGethUrl() {

        return R.success(ethHttpServiceProperties.getUrl());
    }

    @Override
    public R<String> adminDatadir() {
        try {
            String result = geth.adminDatadir().send().getResult();
            return R.success(result);
        } catch (IOException e) {
            log.error("{}", e);
            return R.fail("操作失败");
        }
    }

    @Override
    public R<String> adminPeers() {
        try {
            Object result = geth.adminPeers().send().getResult();
            String json = JSONArray.toJSONString(result.toString());
            return R.success(json);
        } catch (IOException e) {
            log.error("{}", e);
            return R.fail("操作失败");
        }
    }

    @Override
    public R<EthNodeInfo> adminNodeInfo() {
        try {
            EthNodeInfo result = geth.adminNodeInfo().send().getResult();
            return R.success(result);
        } catch (IOException e) {
            log.error("{}", e);
            return R.fail("操作失败");
        }
    }


}
